﻿using System;
using System.ComponentModel;
using Pap.Core.Sync.Configuration;

namespace Pap.Core.Sync
{
    public class SyncAgent
    {
        private EventHandlerList Events { set; get; }

        public ISyncProvider LocalPeer { private set; get; }
        public ISyncProvider ServerPeer { private set; get; }

        public SyncAgent()
        {
            LocalPeer = SyncronizationSection.Instance.CreateLocalPeerProvider();
            ServerPeer = SyncronizationSection.Instance.CreateServerPeerProvider();
            Events = new EventHandlerList();
        }
        public SyncAgent(ISyncProvider local,ISyncProvider server)
        {
            LocalPeer = local;
            ServerPeer = server;
            Events = new EventHandlerList();
        }

        public void Syncronize()
        {
            int totalTableCount = Configuration.SyncronizationSection.Instance.Tables.Count;
            int syncedTableCount = 0;

            LocalPeer.BeginSession();
            ServerPeer.BeginSession();
            OnSyncProgress(new SyncAgentProgressEventArgs(SyncStage.BeginSession, 0, totalTableCount, syncedTableCount,
                                                          string.Empty));

            foreach(Table table in Configuration.SyncronizationSection.Instance.Tables)
            {
                // get changes
                var localChanges = LocalPeer.SelectChanges(table.Name);
                var serverChanges = ServerPeer.SelectChanges(table.Name);

                OnSyncProgress(new SyncAgentProgressEventArgs(SyncStage.ReadTableData,
                                                              (int)((double)syncedTableCount / (double)totalTableCount * 100), totalTableCount,
                                                              syncedTableCount, table.Name));
                //-------------------------------------------------------------
                OnTableSync(new SyncTableProgressEventArgs(table.Name, localChanges.Rows.Count, serverChanges.Rows.Count));
                // update data
                if (localChanges.Rows.Count > 0)
                    ServerPeer.ApplyChanges(localChanges);

                if(serverChanges.Rows.Count > 0)
                LocalPeer.ApplyChanges(serverChanges);
                
                syncedTableCount++;
                OnSyncProgress(new SyncAgentProgressEventArgs(SyncStage.ApplyTableChanges,
                                                              (int)((double)syncedTableCount / (double)totalTableCount * 100), totalTableCount,
                                                              syncedTableCount, table.Name));
            }

            LocalPeer.EndSession();
            ServerPeer.EndSession();
            OnSyncProgress(new SyncAgentProgressEventArgs(SyncStage.EndSession, 100, totalTableCount, syncedTableCount,
                                                          string.Empty));
        }

        public event EventHandler<SyncAgentProgressEventArgs> SyncProgress
        {
            add
            {
                this.Events.AddHandler("SyncProgress", value);
            }
            remove
            {
                this.Events.RemoveHandler("SyncProgress", value);
            }
        }
        public event EventHandler<SyncTableProgressEventArgs> TableSync
        {
            add
            {
                this.Events.AddHandler("TableSync", value);
            }
            remove
            {
                this.Events.RemoveHandler("TableSync", value);
            }
        }

        protected virtual void OnSyncProgress(SyncAgentProgressEventArgs e)
        {
            var dlgt = Events["SyncProgress"] as EventHandler<SyncAgentProgressEventArgs>;
            if(dlgt != null)
                dlgt(this, e);
        }
        protected virtual  void OnTableSync(SyncTableProgressEventArgs e)
        {
            var dlgt = Events["TableSync"] as EventHandler<SyncTableProgressEventArgs>;
            if (dlgt != null)
                dlgt(this, e);
        }

    }
}